﻿using System;
using System.Linq.Expressions;
using Library.Collections.Generic;

namespace Library.Distributed
{
    public abstract class Platform : IMapCollection<object, IDistributed>
    {
        public static Platform Current
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public abstract object NewObjectId();
        public abstract bool TryGetValue(object key, out IDistributed value);
        public bool TrySetValue(object key, IDistributed value)
        {
            if (!ContainsKey(key) || RemoveKey(key))
            {
                if (Add(key, value)) return true;
            }
            return false;
        }
        public abstract bool Add(object key, IDistributed value);
        public abstract bool Contains(object key, IDistributed value);
        public abstract bool ContainsKey(object key);
        public abstract bool Remove(object key, IDistributed value);
        public abstract bool RemoveKey(object key);

        public abstract void Invoke<TElement>(IDistributed<TElement> distributed, Expression<Action<TElement>> local);
        //public abstract void Invoke<TElement>(IDistributed<TElement> distributed, Expression<Func<Context, Context>> subset, Expression<Action<TElement>> local);
        //public abstract void Invoke<TElement>(IDistributed<TElement> distributed, Node node, Expression<Action<TElement>> local);

        public abstract TResult Invoke<TElement, TIntermediate, TResult>(IDistributed<TElement> distributed, Expression<Func<TElement, TIntermediate>> local, Expression<Func<Context, TIntermediate, TResult>> reduction);
        //public abstract TResult Invoke<TElement, TIntermediate, TResult>(IDistributed<TElement> distributed, Expression<Func<Context, Context>> subset, Expression<Func<TElement, TIntermediate>> local, Expression<Func<Context, TIntermediate, TResult>> reduction);
        //public abstract TResult Invoke<TElement, TIntermediate, TResult>(IDistributed<TElement> distributed, Node node, Expression<Func<TElement, TIntermediate>> local, Expression<Func<Context, TIntermediate, TResult>> reduction);

        bool IIsReadOnly.IsReadOnly
        {
            get { return false; }
        }

        IDistributed IMap<object, IDistributed>.this[object key]
        {
            get
            {
                IDistributed retval;
                if (TryGetValue(key, out retval))
                    return retval;
                else
                    throw new System.Collections.Generic.KeyNotFoundException();
            }
            set
            {
                if (!ContainsKey(key) || RemoveKey(key))
                {
                    if (Add(key, value)) return;
                }

                throw new InvalidOperationException();
            }
        }

        IDistributed IMapReadOnly<object, IDistributed>.this[object key]
        {
            get
            {
                IDistributed retval;
                if (TryGetValue(key, out retval))
                    return retval;
                else
                    throw new System.Collections.Generic.KeyNotFoundException();
            }
        }

        IDistributed IMapWriteOnly<object, IDistributed>.this[object key]
        {
            set
            {
                if (!ContainsKey(key) || RemoveKey(key))
                {
                    if (Add(key, value)) return;
                }

                throw new InvalidOperationException();
            }
        }
    }
}
